// dertmap.cpp : Defines the entry point for the console application.
//

// Standard Includes
#include <stdio.h>
#include <assert.h>
#include <ctime>

// SDL
#include "SDL.h"
#include "SDL_ttf.h"
#include "SDL_mixer.h"

// STL
#include <vector>
#include <list>
#include <map>
#include <string>

using namespace std;

#include "SDLSurfaceCache.h"
#include "dertmap.h"
#include "GameBase.h"
#include "DertTerritory.h"

SurfaceCacheInitEntry_t DertMapGraphics[] = 
{
	{ P0_COLOR, 			RESOURCEPATH"P0_50.bmp" },
	{ P1_COLOR, 			RESOURCEPATH"P1_50.bmp" },
	{ P2_COLOR, 			RESOURCEPATH"P2_50.bmp" },
	{ GEO_FOREST, 			RESOURCEPATH"Geo_forest.bmp" },
	{ GEO_GRASS, 			RESOURCEPATH"Geo_grass.bmp" },
	{ GEO_MOUNTAIN, 		RESOURCEPATH"Geo_mountain.bmp" },
	{ GEO_WATER, 			RESOURCEPATH"Geo_water.bmp" },
	{ CURSOR_SELECT_FROM,	RESOURCEPATH"Attack_from.bmp" },
	{ CURSOR_SELECT_TO,		RESOURCEPATH"Attack_from.bmp" },
	{ 0, 0 }
};
CSDLSurfaceCache DertTerritoryGraphics_g;

//#define USESOUND
#define DEBUGSTATES

int Gameon = 1; // a variable for handling game modes, menus, etc

typedef vector<CDertTerritory*> GameBaseVector;
typedef vector< vector<CDertTerritory*> > GameBaseMatrix;
typedef map<string,CDertTerritoryDynamic*> GameBaseMap;

SDL_Surface* world = NULL; 

#ifdef USESOUND
Mix_Music *Music = NULL;
Mix_Chunk *Flap = NULL;
Mix_Chunk *Blam = NULL;
#endif

SDL_Event event; // datastructure for event handling

int main( int argc, char* args[] )
{
    SDL_Init( SDL_INIT_EVERYTHING );   //Start SDL
	SDL_GrabMode SDL_WM_GrabInput(SDL_GRAB_ON); // grabs all keyboard and mouse use
	SDL_ShowCursor(0);

#ifdef USESOUND
	if(Mix_OpenAudio(22050, MIX_DEFAULT_FORMAT, 2,4096)== -1)
	{
		assert(false);
	}
#endif
	TTF_Init();
	
	// get video size
	const SDL_VideoInfo* myPointer = SDL_GetVideoInfo();

	// setup video size for full screen and number of tiles
	//int x_DesiredResolution = myPointer->current_w;
	//int y_DesiredResolution = myPointer->current_h;
	
	// override to smaller screen to up frame rates
	int x_DesiredResolution = 1280;
	int y_DesiredResolution = 720;
	
	int x_tiles = x_DesiredResolution / 50;
	int y_tiles = (y_DesiredResolution / 50) - 2;
	
	// figure out if we need to center the screen
	int x_border = x_DesiredResolution % 50;
	
	if (x_border != 0)
	{
		x_border /= 2;
	}

	int y_Status = (y_tiles*50);
	printf("Screen Setup - Actual %ix%i - Desired %ix%i - %ix%i Tiles [%i Total]\n",myPointer->current_w, myPointer->current_h, x_DesiredResolution,y_DesiredResolution,x_tiles,y_tiles,x_tiles*y_tiles);
  
	// SDL_OPENGL,  SDL_OPENGLBLIT, 
	world = SDL_SetVideoMode( x_DesiredResolution, y_DesiredResolution, 16, SDL_SWSURFACE); // | SDL_FULLSCREEN); //setup backround, ( width, height, 32bit, what surface? )   

	// Load Graphics
	DertTerritoryGraphics_g.Init(DertMapGraphics);
	
	//------------------------------------------
	//  variables for main gameplay mode
	int Background_X = 0;
	int Background_Y = 0;
	int BackgroundVelocity_X = 0;
	int BackgroundVelocity_Y = 0;
	int Mouse_x = 0, Mouse_y = 0;
	char Fire = 0; 
	unsigned int start,end; 
	
	// seed random # generator
	srand((unsigned int)(time(NULL)));

	// declare world - static sized array of map tiles
	// based on screen size
	// map tiles are never deleted except at shutdown - they change
	GameBaseMatrix World(x_tiles, GameBaseVector(y_tiles,NULL));

	// declare object above map tiles - crosshair, selection boxes, etc. 
	// objects can be deleted from this list
	GameBaseMap Objects;

	// create background surface
	const SDL_PixelFormat& fmt = *(world->format);
	SDL_Surface* pLoad = SDL_CreateRGBSurface(SDL_SWSURFACE,x_DesiredResolution, y_DesiredResolution,
                  fmt.BitsPerPixel,fmt.Rmask,fmt.Gmask,fmt.Bmask,fmt.Amask );
	assert(pLoad!=0);
	SDL_Surface* BackgroundColor;
	if(pLoad != NULL)
	{
		BackgroundColor = SDL_DisplayFormat(pLoad);
		SDL_FreeSurface(pLoad);
	}
	assert(BackgroundColor!=0);
	
#ifdef USESOUND	
	//set sound
	Music = Mix_LoadMUS(RESOURCEPATH"DuckRiff22050.wav");
	if(Music == NULL)
	{
		assert(false);
	}

	Blam = Mix_LoadWAV(RESOURCEPATH"GUNSHOT.WAV");
	if (Blam == NULL)
	{
		assert(false);
	}
#endif
	
	// load save game
	// World.push_back(new BitmapObjectStatic(0,0,".\\DertyDucksGraphics\\Background.bmp"));
	// background needs to be first
	// New object \/ below

	// outer loop is X
	// inner loop is Y

	for (int outerloop = 0 ; outerloop < x_tiles; outerloop++)
	{
		for(int innerloop = 0; innerloop < y_tiles; innerloop++)
		{
			CDertTerritory* X = new CDertTerritory((outerloop*50)+x_border,innerloop*50,(GeoType)(rand()%4),(rand()%2)+1);
			World[outerloop][innerloop] = X;
		}
	}

	// New objects /\ above
	// Crosshair needs to be last
	BitmapObject Pointer(200,200,RESOURCEPATH"crosshair.bmp");

	TextObjectStatic PlayerIndicator(x_border,y_Status+5,RESOURCEPATH"SLICKER.TTF" , 40 );
	TextObjectStatic PlayerStateText(x_border,y_Status+5+50,RESOURCEPATH"SLICKER.TTF" , 40 );

	char ScoreString[512] = "";
	
	//------------------------------------------	
	unsigned long frameCount = 1;
	unsigned long framesPerSecond = 1;

#ifdef USESOUND
	if(Mix_PlayMusic(Music, -1) == -1)
	{
		assert(false);
	}
#endif

	// Red is 1
	// Green is 2
	int PlayerTurn = 1;
	
	// State 1 is select source country
		// must match player color
	// State 2 is select to country
		// must not be player color
	// State 3 is Attack
		// both select from and select to will be in dynamic objects
		// animate attack
	// State 4 is Move Armies if win
	// State 5 switches to other player number and resets state
	int PlayerState = 1;
	
	
	while(Gameon == 1)// Main gameplay mode
	{
		start = SDL_GetTicks();

		GameBase::Event EventToPass = GameBase::None;	

		// eat all events
		while(SDL_PollEvent(&event))
		{
			switch (event.type)
			{	
				case SDL_KEYDOWN:
					switch (event.key.keysym.sym)
					{						
						case SDLK_ESCAPE:
							SDL_Quit();
							return 0;  
						break;
					}
					break;
				
				 case SDL_MOUSEMOTION:
						{
							Mouse_x = event.motion.x;
							Mouse_y = event.motion.y;

							BackgroundVelocity_X = Mouse_x;
							BackgroundVelocity_Y = Mouse_y;
						}
				 break; 
				 
				 case SDL_MOUSEBUTTONDOWN:
					 

				 break;

				 case SDL_MOUSEBUTTONUP:
					EventToPass = GameBase::Select;
#ifdef USESOUND
					if(Mix_PlayChannel(-1, Blam, 0) == -1)
					{
						assert(false);
					}
#endif					
				 break;
	

			}	 
		}// end event whileloop

		// handle moving reticle which is always last item to paint
		int x;
		int y;

		Pointer.Move(BackgroundVelocity_X,BackgroundVelocity_Y);
		Pointer.GetPosition(x,y);
		
		// paint background
		SDL_Rect offset;
		offset.x = 0;
		offset.y = 0;    
		SDL_BlitSurface( BackgroundColor, NULL, world, &offset );

		// paint entire world
		for (int outerloop = 0 ; outerloop < x_tiles; outerloop++)
		{
			for(int innerloop = 0; innerloop < y_tiles; innerloop++)
			{
				CDertTerritory* pThisTile = World[outerloop][innerloop];
				
				GameBase::ActionReturn ThisActionReturn;
			
				switch(PlayerState)
				{
					// State 1 is select from country
					// so color must match PlayerTurn
					case(1):				
						if (pThisTile->GetPlayer() == PlayerTurn)
						{
							ThisActionReturn = pThisTile->Action(EventToPass,x,y);
							if (ThisActionReturn == GameBase::Selected)
							{
								// remove other select from objects
								Objects.erase("97selectfrom");
								
								// get x and y of selected square
								int selection_x;
								int selection_y;
								pThisTile->GetPosition(selection_x, selection_y);
								Objects.insert(GameBaseMap::value_type("97selectfrom",new CDertTerritoryDynamic(selection_x,selection_y,CURSOR_SELECT_FROM,pThisTile)));
								
								PlayerState = 2;
								
#ifdef DEBUGSTATES
								printf("Player %i - State 1->%i\n",PlayerTurn,PlayerState);
#endif		
							}
						}  // make sure tile matches
						break;
					
					// state 2 is select attack to 
					// so if next tile does not match player start attack
					// else change select from to new tile	
					case(2):
						ThisActionReturn = pThisTile->Action(EventToPass,x,y);
						if (ThisActionReturn == GameBase::Selected)
						{
							// add new object
							int selection_x;
							int selection_y;
							pThisTile->GetPosition(selection_x, selection_y);
								
							// if we select another or our own tiles that is a new from
							if (pThisTile->GetPlayer() == PlayerTurn)
							{
								// remove other select from objects
								Objects.erase("97selectfrom");
									
								Objects.insert(GameBaseMap::value_type("97selectfrom",new CDertTerritoryDynamic(selection_x,selection_y,CURSOR_SELECT_FROM,pThisTile)));
							
#ifdef DEBUGSTATES
									printf("Player %i - Staying in State %i\n",PlayerTurn,PlayerState);
#endif								
							}
							else
							{
								// need to check proximity rules
								// assume proximity check OK
								
								// remove other selectto objects (should be none)
								Objects.erase("96selectto");
									
								// add new object
								Objects.insert(GameBaseMap::value_type("96selectto",new CDertTerritoryDynamic(selection_x,selection_y,CURSOR_SELECT_TO,pThisTile)));
								
								PlayerState = 3;
								
#ifdef DEBUGSTATES
									printf("Player %i - State 2->%i\n",PlayerTurn,PlayerState);
#endif									
							}
						}
						break;
						
					case(3):
						{
							// switch outline mode of selected cells ?
							// do attack
							GameBaseMap::iterator From = Objects.find("97selectfrom");
							GameBaseMap::iterator To = Objects.find("96selectto");
							
							if ( (From != Objects.end()) && (To != Objects.end()) )
							{
								To->second->GetObjRef()->SetPlayer( (rand() %2) +1);
								PlayerState = 4;
#ifdef DEBUGSTATES
								printf("Player %i - State 3->%i\n",PlayerTurn,PlayerState);
#endif									
							}
						}
						break;
					
					case(4):
						// erase selection square
						// remove other select from objects
						Objects.erase("97selectfrom");								
						Objects.erase("96selectto");
						
						// switch player
						PlayerTurn++;
						if (PlayerTurn == 3)
						{
							PlayerTurn=1;
						}
						// Set state back to 1
						PlayerState = 1;
						
#ifdef DEBUGSTATES
						printf("Player %i - Restart State %i\n",PlayerTurn,PlayerState);
#endif							
						break;
						
				}  // end switch
					
				// draw tile regardless
				pThisTile->Draw(world);	
			}
		}
		
		// Draw Dynamic Objects
		GameBaseMap::iterator iter = Objects.begin();
		while(iter != Objects.end() )
		{
			if(iter->second->GetActive())
			{
				iter->second->Draw(world);

				// next object
				iter++;
			}
			else
			{
				Objects.erase(iter);	
				iter = Objects.begin();
			}
		}  
		
		// Update Strings
		int R,G,B;
		switch(PlayerTurn)
		{
			case(1):
				sprintf(ScoreString,"Red Turn");
				R=255;
				G=0;
				B=0;
				break;
				
			case(2):
				sprintf(ScoreString,"Green Turn");
				R=0;
				G=255;
				B=0;
				break;
				
			default:
				assert(false);
				break;
		}
		PlayerIndicator.SetText(world, ScoreString, R, G, B);
		
		switch(PlayerState)
		{
			case(1):
				strcpy(ScoreString,"Select Source Country To Attack From");
				break;
			case(2):
				strcpy(ScoreString,"Select Destination Country To Attack");
				break;
			case(3):
				strcpy(ScoreString,"Battle Underway");
				break;
			case(4):
				strcpy(ScoreString,"Distribute Troops");
				break;
			case(5):
				PlayerTurn++;
				if (PlayerTurn == 3)
				{
					PlayerTurn = 1;
				}
				PlayerState = 1;
				break;
		}
		PlayerStateText.SetText(world, ScoreString, R, G, B);

		// draw crosshair last
		Pointer.Draw(world);
		
		SDL_Flip(world); //updates screen,
		end = SDL_GetTicks(); 
		
		framesPerSecond = end - start;
		frameCount++; 
		SDL_Delay(1);

	}//end maingameplay whileloop
	
	// free dynamic objects
	for(GameBaseMap::iterator iter = Objects.begin() ; iter != Objects.end() ; iter++)
	{
		delete iter->second;
		iter->second = 0;
	}
	
	// free entire world
	for (int outerloop = 0 ; outerloop < 20; outerloop++)
	{
		for(int innerloop = 0; innerloop < 20; innerloop++)
		{
			GameBase* pThisTile = World[outerloop][innerloop];
			if(pThisTile->GetActive())
			{
				delete pThisTile;
				World[outerloop][innerloop] = 0;
			}
		}
	}

	// free background 
	SDL_FreeSurface(BackgroundColor);
	
	SDL_Quit();
	return 0;   
    
}
